package hasthi.container;

import hasthi.common.BaseContext;
import hasthi.common.HasthiException;
import hasthi.common.HasthiOptions;
import hasthi.common.HasthiException.FaultCode;
import hasthi.common.constants.WSDMConstants;
import hasthi.wsdm.ManagedServiceHandle;
import hasthi.wsdm.ManagedSystemHandle;
import hasthi.wsdm.ManagementAgentContext;
import hasthi.wsdm.ManagementAgentUtils;

import java.util.Map;
import java.util.Properties;

import javax.xml.namespace.QName;

import org.apache.xmlbeans.XmlObject;
import org.xmlpull.v1.builder.XmlDocument;

import xsul.message_router.MessageContext;
import xsul.message_router.MessageProcessingException;
import xsul.message_router.MessageRouterException;
import xsul.soap.SoapUtil;
import xsul.soap11_util.Soap11Util;
import xsul.soap12_util.Soap12Util;
import xsul.ws_addressing.WsaMessageInformationHeaders;
import xsul.wsdl.WsdlDefinitions;
import xsul.xbeans_util.XBeansUtil;
import xsul.xservices_xbeans.XmlBeansBasedService;
import xsul.xservo_soap_http.HttpBasedServices;

/**
 * This is a Wrapper around XBeans based Services that would provide management
 * instrumentation
 */

public class ExtendedXbeanBasedService extends XmlBeansBasedService {
    private XsulBasedWSDMProcessor processor;
    private ManagedSystemHandle systemHandle;

 
    
    
    private QName serviceName = null;
    private boolean collectRequestStats = false;

    public ExtendedXbeanBasedService(String name, String wsdlLoc, Object serviceImpl,
            QName serviceName) throws HasthiException {
        super(name, wsdlLoc, serviceImpl);
        this.serviceName = serviceName;
    }

    public ExtendedXbeanBasedService(String name, String wsdlLoc, Object serviceImpl)
            throws HasthiException {
        super(name, wsdlLoc, serviceImpl);

    }

    public ExtendedXbeanBasedService(String name) throws HasthiException {
        super(name);
    }

    @Override
    public boolean process(MessageContext messageContext) throws MessageProcessingException {
        try {
            WsaMessageInformationHeaders addrHeader = new WsaMessageInformationHeaders(messageContext.getIncomingEnvelope());
            if (addrHeader.getAction() != null && processor.isKnownMessage(addrHeader.getAction().toString())) {
                XSULMessageContext hasthiMessageContext = new XSULMessageContext(messageContext
                        .getIncomingEnvelopeDoc(), getWsdlLocationToUse().replace("?wsdl", ""));

                SoapUtil soapUtil = SoapUtil.selectSoapFragrance(messageContext
                        .getIncomingEnvelopeDoc(), new SoapUtil[] { Soap12Util.getInstance(),
                        Soap11Util.getInstance() });
                XmlObject responseAsXmlbeans = processor.processeMessage(hasthiMessageContext);
                XmlDocument responseDocument = soapUtil.wrapBodyContent(XBeansUtil
                        .xmlObjectToXmlElement(responseAsXmlbeans));
                messageContext.setOutgoingMessage(responseDocument.getDocumentElement());
                return true;
            } else {
                if (!collectRequestStats) {
                    return super.process(messageContext);
                } else {
                    try {
                        long start = System.currentTimeMillis();
                        ((ManagedServiceHandle) (systemHandle)).requestRecived();
                        boolean retVal = super.process(messageContext);
                        ((ManagedServiceHandle) (systemHandle)).requestSucessful(System
                                .currentTimeMillis()
                                - start);
                        return retVal;
                    } catch (Exception e) {
                        ((ManagedServiceHandle) (systemHandle)).requestFalied();
                        throw new MessageProcessingException(e.getMessage(), e);
                    }
                }
            }
        } catch (HasthiException e) {
            throw new MessageProcessingException(e.getMessage(), e);
        }
    }

    
    public void initManagmentAgent() throws HasthiException{
        String bootstrapNode = System.getProperty(HasthiOptions.BOOTSTRAP_NODE);
        if(bootstrapNode == null){
            throw new HasthiException("can not find bootstrapNode for Hasthi, please set the system property"+HasthiOptions.BOOTSTRAP_NODE+" (this can be set via " +
            		"System.setProperty(..) or jvm parameter -D"+HasthiOptions.BOOTSTRAP_NODE+"=..)",FaultCode.ConfigError);
        }
        initManagmentAgent(bootstrapNode,(HttpBasedServices)null);
    }
    
    
    public void initManagmentAgent(String bootstrapNode,HttpBasedServices httpBasedServices) throws HasthiException{
        WsdlDefinitions wsdl = getWsdl();
        if(wsdl == null){
            throw new HasthiException("can not find wsdl from the service",FaultCode.ConfigError);
        }
        Map<QName, Object> properties = ManagementAgentUtils.createServiceManagementProperties(wsdl);
        QName serviceName = QName.valueOf((String)properties.get(new QName(WSDMConstants.SERVICE_NAME)));
        
        Properties config = new Properties();
        config.setProperty(HasthiOptions.BOOTSTRAP_NODE, bootstrapNode);

        BaseContext baseContext = new BaseContext(config);
        Xsul2SystemHandle systemHandle = new Xsul2SystemHandle(serviceName,serviceName,serviceName.getLocalPart(),
                properties,this);
        systemHandle.setHttpBasedServices(httpBasedServices);
        initManagmentAgent(baseContext, systemHandle);
    }
    
    
    public void initManagmentAgent(String bootstrapNode,ManagedSystemHandle systemHandle) throws HasthiException{
        WsdlDefinitions wsdl = getWsdl();
        if(wsdl == null){
            throw new HasthiException("can not find wsdl from the service",FaultCode.ConfigError);
        }
        Properties config = new Properties();
        config.setProperty(HasthiOptions.BOOTSTRAP_NODE, bootstrapNode);

        BaseContext baseContext = new BaseContext(config);
        initManagmentAgent(baseContext, systemHandle);
    }

   

 
    public void initManagmentAgent(BaseContext baseContext,ManagedSystemHandle systemHandle)
            throws HasthiException {
        collectRequestStats = systemHandle instanceof ManagedServiceHandle;
        ManagementAgentContext context = new ManagementAgentContext(baseContext);
        processor = new XsulBasedWSDMProcessor(context);
        processor.addResource(systemHandle);
        this.systemHandle = systemHandle;
    }

    public void setIfNotset(ManagedSystemHandle systemHandle, QName name, String value) {

    }

    @Override
    public void shutdownService() throws MessageRouterException {
        try {
            processor.shutdown();
            super.shutdownService();
        } catch (HasthiException e) {
            throw new MessageRouterException("Failed while shutting down the service", e);
        }
    }

    @Override
    public void stopService() throws MessageRouterException {
        try {
            processor.shutdown();
            super.shutdownService();
        } catch (HasthiException e) {
            throw new MessageRouterException("Failed while shutting down the service", e);
        }
        super.stopService();
    }
    
    
    
}
